/**
 * 
 */
package gs.eisenhower.swallet.utils.methods;

import static gs.eisenhower.swallet.utils.constants.WalletConstants.EMPTY;
import static gs.eisenhower.swallet.utils.constants.WalletConstants.Q_MARK;

/**
 * @author mbadarau
 */
public class QueryBuilder {

    private StringBuilder sb = new StringBuilder();

    private static final String Select = "SELECT";
    private static final String Delete = "DELETE";
    private static final String SelectDistinct = "SELECT DISTINCT";
    @SuppressWarnings("unused")
	private static final String Count = "COUNT";
    private static final String From = "FROM";
    private static final String Where = "WHERE";
    private static final String InnerJoin = "INNER JOIN";
    @SuppressWarnings("unused")
	private static final String LeftOuterJoin = "LEFT OUTER JOIN";
    private static final String OrderBy = "ORDER BY";
    private static final String As = "AS";
    private static final String Desc = "DESC";
    @SuppressWarnings("unused")
	private static final String Asc = "ASC";
    private static final String On = "ON";
    @SuppressWarnings("unused")
	private static final String And = "AND";
    private static final String Primary_Key = "id";

    public QueryBuilder() {

    }

    public QueryBuilder(String someSqlCode) {
        sb.append(someSqlCode);
    }

    /**
     * @param selectClause
     * @return
     */
    public QueryBuilder SELECT(String selectClause) {
        constructSelect(Select, selectClause);
        return this;
    }

    /**
     * @param fields
     * @return
     */
//    public QueryBuilder SELECT(EnumerableFields... fields) {
//        SELECT();
//        constructSelect(fields);
//        return this;
//    }

    /**
     * @param fields
     * @return
     */
//    public QueryBuilder SELECT_DISTINCT(EnumerableFields... fields) {
//        SELECT_DISTINCT();
//        constructSelect(fields);
//        return this;
//    }

    /**
     * @param selectClause
     * @return
     */
    public QueryBuilder SELECT_DISTINCT(String selectClause) {
        constructSelect(SelectDistinct, selectClause);
        return this;
    }

    /**
     * @return
     */
    public QueryBuilder SELECT() {
        constructSelect(Select, EMPTY);
        return this;
    }

    /**
     * @return
     */
    public QueryBuilder SELECT_DISTINCT() {
        constructSelect(SelectDistinct, EMPTY);
        return this;
    }

    public QueryBuilder COUNT(String countClause) {
        return this;
    }

    /**
     * @param fields
     * @return
     */
//    public QueryBuilder COUNT(EnumerableFields fields) {
//        sb.append(String.format(" %1$s (%2$s.%3$s) ", Count, fields.getTable().getTableAlias(), fields.getFieldName()));
//        return this;
//    }

    /**
     * @param table
     * @return
     */
    public QueryBuilder FROM(String table, String alias) {
        sb.append(String.format(" %1$s %2$s %3$s ", From, table, alias));
        return this;
    }
    
    public QueryBuilder FROM(String table) {
        sb.append(String.format(" %1$s %2$s ", From, table));
        return this;
    }
    
    /**
     * 
     * @author sgodoroja
     * */
	public QueryBuilder WHERE(String whereClause) {
		sb.append(" WHERE " + whereClause);
		return this;
	}
	
	public QueryBuilder DELETE(String table) {
		sb.append(String.format(" %1$s %2$s %3$s ", Delete, From, table));
		return this;
	}
	
	public QueryBuilder ORDER_BY_DESC() {
		sb.append(String.format(" %1$s %2$s %3$s", OrderBy, Primary_Key, Desc));
		return this;
	}

    /**
     * @param table
     * @return
     */
    public QueryBuilder INNER_JOIN(String joinClause) {
        sb.append(String.format(" %1$s %2$s ", InnerJoin, joinClause));
        return this;
    }

    /**
     * @param table
     * @return
     */
//    public QueryBuilder INNER_JOIN(EnumerableTables table) {
//        sb.append(String.format(" %1$s %2$s %3$s ", InnerJoin, table.getTableName(), table.getTableAlias()));
//        return this;
//    }

//    public QueryBuilder LEFT_OUTER_JOIN(EnumerableTables table) {
//        sb.append(String.format(" %1$s %2$s %3$s ", LeftOuterJoin, table.getTableName(), table.getTableAlias()));
//        return this;
//    }

    /**
     * @param mainField
     * @param secondaryField
     * @return
     */
//    public QueryBuilder ON(EnumerableFields mainField, EnumerableFields secondaryField) {
//        constructMatching(On, mainField.getTable().getTableAlias(), mainField.getFieldName(), secondaryField.getTable()
//                .getTableAlias(), secondaryField.getFieldName());
//        return this;
//    }

    public QueryBuilder ON(String mainAlias, String mainField, String secondaryAlias, String secondaryField) {
        constructMatching(On, mainAlias, mainField, secondaryAlias, secondaryField);
        return this;
    }

    /**
     * Append WHERE clause on a foreign key. Used in case of subselect.
     * 
     * @param mainField
     * @param secondaryField
     * @return
     */
//    public QueryBuilder WHERE(EnumerableFields mainField, EnumerableFields secondaryField) {
//        constructMatching(Where, mainField.getTable().getTableAlias(), mainField.getFieldName(), secondaryField
//                .getTable().getTableAlias(), secondaryField.getFieldName());
//        return this;
//    }

    public QueryBuilder WHERE_WITHOUT_ALIAS(String field) {
        sb.append(String.format(" %1$s %2$s = %3$s ", Where, field, Q_MARK));
        return this;
    }

    /**
     * Append WHERE clause.
     * 
     * @param field
     * @param secondaryField
     * @return
     */ 
//    public QueryBuilder WHERE(EnumerableFields field) {
//        constructFilter(Where, field.getTable().getTableAlias(), field.getFieldName());
//        return this;
//    }

//    /**
//     * Append WHERE clause.
//     * 
//     * @param mainField
//     * @param secondaryField
//     * @return
//     */
//    public QueryBuilder WHERE_CLAUSE_ON_DATE_FILEDS(EnumerableFields mainField) {
//        constructFilterOnDateFields(Where, mainField.getTable().getTableAlias(), mainField.getFieldName());
//        return this;
//    }
    
    /**
     * @param field
     * @return
     */
//    public QueryBuilder ASC(EnumerableFields field) {
//        sb.append(String.format(" %1$s %2$s.%3$s %4$s ", OrderBy, field.getTable().getTableAlias(), field.getFieldName(), Asc));
//        constructFilter(And, field.getTable().getTableAlias(), field.getFieldName());
//        return this;
//    }
    
    /**
     * @param field
     * @return
     */
//    public QueryBuilder DESC(EnumerableFields field) {
//        sb.append(String.format(" %1$s %2$s.%3$s %4$s ", OrderBy, field.getTable().getTableAlias(), field.getFieldName(), Desc));
//        constructFilter(And, field.getTable().getTableAlias(), field.getFieldName());
//        return this;
//    }


    /**
     * @param field
     * @return
     */
//    public QueryBuilder AND(EnumerableFields field) {
//        constructFilter(And, field.getTable().getTableAlias(), field.getFieldName());
//        return this;
//    }

    /**
     * Used to customize your filter matching query. Can be passed EMPTY values for "sqlClause". Alias added on need.
     * 
     * @param field
     * @return
     */
//    public QueryBuilder addCustomizedFilter(EnumerableFields field, final String sqlClause, final boolean isAliasAdded) {
//        if (isAliasAdded) {
//            constructFilter(sqlClause, field.getTable().getTableAlias(), field.getFieldName());
//            return this;
//        }
//        sb.append(String.format(" %1$s %2$s = %3$s ", sqlClause, field.getFieldName(), Q_MARK));
//        return this;
//    }

//    public QueryBuilder AND_CLAUSE_ON_DATE_FIELDS(EnumerableFields mainField) {
//        constructFilterOnDateFields(And, mainField.getTable().getTableAlias(), mainField.getFieldName());
//        return this;
//    }

    /**
     * @param aliasName
     * @return
     */
    public QueryBuilder AS(String aliasName) {
        sb.append(String.format(" %1$s %2$s ", As, aliasName));
        return this;
    }

    public QueryBuilder append(String stringToappend) {
        sb.append(stringToappend);
        return this;
    }

    public QueryBuilder append(QueryBuilder queryBuilder) {
        sb.append(queryBuilder.toString());
        return this;
    }

    public QueryBuilder append(char symbol) {
        sb.append(symbol);
        return this;
    }

    public QueryBuilder append(Object obj) {
        sb.append(obj);
        return this;
    }

    @Override
    public String toString() {
        return sb.toString();
    }

//    private void constructSelect(EnumerableFields... fields) {
//        for (int i = 0; i < fields.length; i++) {
//            sb.append(String.format(" %1$s.%2$s ", fields[i].getTable().getTableAlias(), fields[i].getFieldName()));
//            if (i != fields.length - 1) {
//                sb.append(COMMA);
//            }
//        }
//    }

    private void constructSelect(String selectClause, String selectStatement) {
        sb.append(String.format("%1$s %2$s ", selectClause, selectStatement));
    }

//    private void constructFilter(String sqlStatement, String fieldAlias, String fieldName) {
//        sb.append(String.format(" %1$s %2$s.%3$s = %4$s ", sqlStatement, fieldAlias, fieldName, Q_MARK));
//    }

//    private void constructFilterOnDateFields(String sqlStatement, String fieldAlias, String fieldName) {
//        sb.append(String.format(" %1$s DATE(%2$s.%3$s/1000, 'UNIXEPOCH') = %4$s ", sqlStatement, fieldAlias, fieldName,
//                Q_MARK));
//    }

    private void constructMatching(String sqlStatement, String mainAlias, String mainField, String secondaryAlias,
            String secondaryField) {
        sb.append(String.format(" %1$s %2$s.%3$s = %4$s.%5$s ", sqlStatement, mainAlias, mainField, secondaryAlias,
                secondaryField));
    }

}